package state


import ."api"


// 把键值对写入表
// 其中键和值从栈里弹出，表则位于指定索引处
func (self *luaState) SetTable(idx int) {

	t := self.stack.get(idx)

	v := self.stack.pop()
	k := self.stack.pop()

	self.setTable(t, k, v, false)  // 需要触发元方法
}


// 写表逻辑
// 位于指定索引处的值不是表
// 暂时调用panic()函数汇报错误
func (self *luaState) setTable(t, k, v luaValue, raw bool) {
	if tbl, ok := t.(*luaTable); ok {

		if raw || tbl.get(k) != nil || !tbl.hasMetafield("__newindex") {

			tbl.put(k, v)

			return
		}

	}

	if !raw {

		if mf := getMetafield(t, "__newindex", self); mf != nil {

			switch x := mf.(type) {

			case *luaTable:

				self.setTable(x, k, v, false)

				return

			case *closure:

				self.stack.push(mf)
				self.stack.push(t)
				self.stack.push(k)
				self.stack.push(v)
				self.Call(3, 0)

				return
			}
		}

	}

	panic("not a table!")
}


func (self *luaState) RawSet(idx int) {

	t := self.stack.get(idx)
	v := self.stack.pop()
	k := self.stack.pop()

	self.setTable(t, k, v, true)

}


// 和SetTable()类似，只不过键不是从栈顶弹出的任意值
// 而是由参数传入的字符串
func (self *luaState) SetField(idx int, k string) {

	t := self.stack.get(idx)
	v := self.stack.pop()

	self.setTable(t, k, v, false)  // 需要触发元方法
}


// 和SetI类似
// 只不过由参数传入的键是数字而非字符串
func (self *luaState) SetI(idx int, i int64) {

	t := self.stack.get(idx)
	v := self.stack.pop()

	self.setTable(t, i, v, false)  // 需要触发元方法
}


func (self *luaState) RawSetI(idx int, i int64) {

	t := self.stack.get(idx)
	v := self.stack.pop()

	self.setTable(t, i, v, false)  // 不需要触发元方法
}


// 从栈顶弹出一个值
// 如果它是nil，实际效果就是清除元表
// 然后把指定索引处值的元表设置成该表
func (self *luaState) SetMetatable(idx int) {

	val := self.stack.get(idx)

	mtVal := self.stack.pop()

	if mtVal == nil {

		setMetatable(val, nil, self)
	} else if mt, ok := mtVal.(*luaTable); ok {

		setMetatable(val, mt, self)
	} else {

		panic("table expected!")  // TODO
	}

}


// 往全局环境写入一个值，其中字段名由参数指定，值从栈顶弹出
func (self *luaState) SetGlobal(name string) {

	t := self.registry.get(LUA_RIDX_GLOBALS)

	v := self.stack.pop()

	self.setTable(t, name, v, false)

}